#!/usr/bin/env python
import sys,os
sys.path += ["/Library/Python/2.6/site-packages/ply-3.4-py2.6.egg"]

import ply.lex as lex
import ply.yacc as yacc

def indentedWithHeader(s, b):
	TAB = "\t"
	o = "%!PS-Adobe-3.0 EPSF-3.0\n%%BoundingBox: -3 -3 3 3\n"
	if not b: return o + s
	s = s.split(" ")
	t = 0
	for w in s:
		if w in ["{", "gsave"]:
			t += 1
			o += w
			o += "\n" + TAB * t
		elif w in ["translate", "rotate", "scale", "circ", "box", "repeat", "def"]:
			o += w
			o += "\n" + TAB * t
		elif w in ["grestore", "}"]:
			t -= 1
			if o[-len(TAB):] == TAB:
				o = o[:-len(TAB)]
			o += w + " "
			if w != "}":
				o += "\n" + TAB * t
		elif w[0] == "." or w[0] == "-" or w[0] in "0123456789":
			o += w + " "
		else:
			o += w + "\n" + TAB * t
	return o

class Parser:
	#=====================================================================
	# Base class for a lexer/parser that has the rules defined as methods
	#=====================================================================
	tokens = ()
	precedence = ()

	def __init__(self, **kw):
		self.debug = kw.get("debug", 0)
		self.names = {}
		try:
			modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
		except:
			modname = "parser"+"_"+self.__class__.__name__
		modname = "_" + modname
		self.debugfile = modname + ".dbg"
		self.tabmodule = modname + "_" + "parsetab"
		#print self.debugfile, self.tabmodule
		
		# Build the lexer and parser
		self.lexer = lex.lex(module=self, debug=self.debug)
		yacc.yacc(module=self, debug=self.debug,
			debugfile=self.debugfile,
			tabmodule=self.tabmodule
		)
	
	def lineChar(self, lexpos):
		lexpos = min(lexpos, len(self.lexer.lexdata)-1)
		nline = 1
		nchar = 1
		for i in xrange(lexpos):
			if self.lexer.lexdata[i] == "\n":
				nline += 1
				nchar = 1
			else: nchar += 1
		return nline, nchar
	
	def line(self, nline):
		if nline <= 0: return ""
		if nline > self.lexer.lexdata.count("\n") + 1: return ""
		return self.lexer.lexdata.split("\n")[nline-1].replace("\t", " ")
	
	def error(self, nchar, desc):
		lc = self.lineChar(nchar)
		
		line = self.line(lc[0])
		pref = "    "
		lstart = len(pref)
		while line[0] == " ":
			line = line[1:]
			lstart -= 1
		if nchar > 0:
			print >> sys.stderr, "  Line %d, character %d" % lc
			print >> sys.stderr, pref + line
			print >> sys.stderr, " " * (lc[1]-1 + lstart) + "^"
		print >> sys.stderr, desc
		exit(1)
		
	def parse(self, s):
		return yacc.parse(s)
	

class Graphic:
	def __init__(self):
		self.code = ""
		self.labels = []
	def __str__(self):
		return str(self.code) + ", " + str(self.labels)

class FParser(Parser):
	# ==============================
	# TOKENS
	# ==============================	
	
	reserved = {
		"circle":"CIRCLE",
		"box":   "BOX",
		"move":  "MOVE",
		"scale": "SCALE",
		"rotate":"ROTATE",
		"define":"DEFINE",
		"repeat":"REPEAT"
	}
	
	tokens = ["NOTNATURAL", "NATURAL", "LPAREN", "RPAREN", "LABEL"] + list(reserved.values())
	
	t_LPAREN = r"\("
	t_RPAREN = r"\)"
	t_NOTNATURAL = r"([-+]?[0-9]*\.[0-9]+)|(-[0-9]+)"
	t_NATURAL = r"[+]?[0-9]+"
	t_ignore = " \t\n"
	
	def t_LABEL(self, t):
		r"[a-zA-Z]+"
		t.type=self.reserved.get(t.value.lower(),"LABEL")
		return t

	def t_error(self, t):
		self.error(t.lexer.lexpos, "SyntaxError: invalid character '%s'" % t.value[0])
		
	
	# ==============================
	# PARSING RULES
	# ==============================	
	def p_statement_graphic(self, p):
		"""statement : graphic
				     | graphicUnion"""
		
		s = []
		for l in p[1].labels:
			if l[0] == "U" and not l[1:] in s:
				input = self.lexer.lexdata.replace("\t", " ").replace("\n", " ").lower()
				i = input.find(" %s " % l[1:]) + 1
				if i < 0: i = input.find("%s " % l[1:])
				if i < 0: i = input.find(" %s" % l[1:]) + 1
				if i < 0: i = input.find("%s" % l[1:])
				i += len(l[1:]) - 1
				self.error(i, "SyntaxError: name '%s' is not defined" % l[1:])
			if l[0] == "D": s += [l[1:]]
		
		p[0] = ""
		p[0] += "5 dict begin "
		p[0] += "/box { "
		p[0] += "0 0 moveto 0 1 lineto 1 1 lineto 1 0 lineto closepath fill "
		p[0] += "} def "
		p[0] += "/circ { "
		p[0] += "0 0 1 0 360 arc closepath fill "
		p[0] += "} def "
		p[0] += p[1].code
		p[0] += " end "
		p[0] += "showpage"
		
	def p_graphic_circle(self, p):
		"graphic : CIRCLE num"
		p[0] = Graphic()
		if abs(float(p[2]) - 1.0) < 0.00000001: #sin escalar
			p[0].code = "circ"
		else:
			p[0].code = "%s %s scale circ" % (p[2], p[2])
		
	def p_graphic_box(self, p):
		"graphic : BOX num num"
		p[0] = Graphic()
		if abs(float(p[2]) - 1.0) < 0.00000001 and abs(float(p[3]) - 1.0) < 0.00000001: #sin escalar
			p[0].code = "box"
		else:
			p[0].code = "%s %s scale box" % (p[2], p[3])
		
	def p_graphic_move(self, p):
		"graphic : MOVE num num graphic"
		p[0] = Graphic()
		p[0].code = "%s %s translate %s" % (p[2], p[3], p[4].code)
		p[0].labels = p[4].labels
		
	def p_graphic_scale(self, p):
		"graphic : SCALE num num graphic"
		p[0] = Graphic()
		p[0].code = "%s %s scale %s" % (p[2], p[3], p[4].code)
		p[0].labels = p[4].labels
		
	def p_graphic_rotate(self, p):
		"graphic : ROTATE num graphic"
		p[0] = Graphic()
		p[0].code = "%s rotate %s" % (p[2], p[3].code)
		p[0].labels = p[3].labels
		
	def p_graphic_repeat(self, p):
		"graphic : REPEAT NATURAL num num graphic"
		p[0] = Graphic()
		p[0].code = "%d { gsave %s grestore %s %s translate } repeat" % (int(p[2]), p[5].code, p[3], p[4])
		p[0].labels = p[5].labels
		
	def p_graphic_define(self, p):
		"graphic : DEFINE LABEL graphic"
		p[0] = Graphic()
		p[0].code = "/_%s { %s } def" % (p[2].lower(), p[3].code)
		p[0].labels = p[3].labels + ["D" + p[2].lower()]
		
	def p_graphic_label(self, p):
		"graphic : LABEL"
		p[0] = Graphic()
		p[0].code = "_" + p[1].lower()
		p[0].labels += ["U" + p[1].lower()]
		
	def p_graphic_group(self, p):
		"""graphic : LPAREN graphic RPAREN
				   | LPAREN graphicUnion RPAREN"""
		p[0] = Graphic()
		p[0].code = p[2].code
		p[0].labels = p[2].labels
		
 	def p_graphic_union_rec(self, p):
		"graphicUnion : graphicUnion graphic"
		p[0] = Graphic()
		p[0].code = "gsave %s grestore gsave %s grestore" % (p[1].code, p[2].code)
		p[0].labels = p[1].labels + p[2].labels
	
	def p_graphic_union_base(self, p):
		"graphicUnion : graphic"
		p[0] = Graphic()
		p[0].code = p[1].code
		p[0].labels = p[1].labels
	
	def p_num_numbers(self, p):
		"""num : NATURAL
			   | NOTNATURAL"""
		p[0] = p[1]
	
	
	def p_error(self, p):
		if p == None:
			self.error(self.lexer.lexpos, "SyntaxError: incomplete sentence")
			
		else:
			self.error(self.lexer.lexpos-1, "SyntaxError: invalid syntax at '%s'" % p.value)


fparser = FParser()
s = sys.stdin.read()
if not s: exit(0)
output = fparser.parse(s)
indent = (len(sys.argv) >= 2 and "-i" in [v.lower() for v in sys.argv])
print indentedWithHeader(output, indent) if output else ""
